import { DICT } from '../../dict/dict';
import { knnoButton } from '../../theme/button.css';
import { actionQueue } from '../../tools/actionQueue';
import { DialogBase } from '../dialogBase';
import { DATA } from '../symbol';
import { actionStyle } from './action.css';

class ActionBox extends DialogBase<ActionBox> {
	get panel(): HTMLElement {
		return this.el.querySelector(`div.${actionStyle}>div.panel`)!;
	}

	protected get contentBox(): HTMLDivElement {
		return this.el.querySelector(`div.${actionStyle}>div.panel>div.content`)!;
	}

	protected render() {
		return (
			<div class={actionStyle}>
				<div class="panel" tabIndex={0}>
					<div class="button-bar"></div>
					<div class="content"></div>
				</div>
			</div>
		);
	}

	private renderBar() {
		const bar = this.el.querySelector(':scope>div.panel>div.button-bar')!;
		const fragment = (<></>) as DocumentFragment;
		if (typeof this[DATA].onOk === 'function' && !this[DATA].noBar) {
			bar.classList.add('has-button');
			fragment.append(
				<button
					type="button"
					class={[knnoButton, 'text']}
					onClick={() => {
						this.el.dispatchEvent(new Event('close'));
					}}
				>
					{DICT.cancel}
				</button>,
				<h4>{this[DATA].title ?? ''}</h4>,
				<button
					type="button"
					class={[knnoButton, 'primary-text']}
					onClick={() => {
						this[DATA].onOk?.call(this);
					}}
				>
					{DICT.ok}
				</button>,
			);
		} else {
			bar.classList.remove('has-button');
			fragment.append(<h4>{this[DATA].title ?? ''}</h4>);
		}
		if (this[DATA].title && !this[DATA].noBar) {
			bar.classList.add('has-title');
		} else {
			bar.classList.remove('has-title');
		}
		bar.replaceChildren(fragment);
	}

	onOK(callback: ((this: ActionBox) => void) | null): this {
		if (callback) {
			this[DATA].onOk = callback;
		} else {
			delete this[DATA].onOk;
		}
		this.renderBar();
		return this;
	}

	setTitle(text: string | null): this {
		if (text) {
			this[DATA].title = text;
		} else {
			delete this[DATA].title;
		}
		this.renderBar();
		return this;
	}

	setNoBar(value: boolean): this {
		this[DATA].noBar = value;
		this.renderBar();
		return this;
	}

	setContent(elem: (Node | string)[] | Node | string): this {
		if (Array.isArray(elem)) {
			this.contentBox.replaceChildren(...elem);
		} else {
			this.contentBox.replaceChildren(elem);
		}
		return this;
	}

	setAlign(align: 'bottom' | 'top' | 'left' | 'right'): this {
		this.el.classList.remove('bottom', 'top', 'left', 'right');
		this.el.classList.add(align);
		return this;
	}

	addClass(cls: string): this {
		this.el.classList.add(...cls.split(/\s+/g).filter((v) => !!v));
		return this;
	}
}

interface ActionEntry {
	action: ActionBox;
	show(): void;
	hide(): void;
}

const queue = actionQueue<ActionEntry>(200);

let currentAction: ActionEntry | null = null;

interface ActionOption {
	align?: 'bottom' | 'top' | 'left' | 'right';
	autoClose?: boolean;
}

export const Action = {
	get current() {
		return currentAction;
	},
	show(elem: (Node | string)[] | Node | string, options?: ActionOption) {
		const autoClose = options?.autoClose ?? true;
		const actionEntry = {
			action: new ActionBox({})
				.setAlign(options?.align ?? 'bottom')
				.setContent(elem)
				.setAutoClose(true)
				.onClose((result) => {
					if (autoClose) {
						queue.close(result.esc ?? false);
					}
				}),
			show() {
				this.action.show();
				currentAction = actionEntry;
			},
			hide() {
				currentAction = null;
				this.action.close();
			},
		};
		if (autoClose) {
			queue.show(actionEntry);
		} else {
			actionEntry.action.show();
		}
		return actionEntry.action;
	},
	close(esc: boolean) {
		queue.close(esc);
	},
};

DialogBase.actionHandler = Action;
